﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Meta.Numerics.Statistics.Distributions;

namespace ExcelAddIn1
{
    /**
     * Implementation of a chi-square test for independence.
     */
    class Test_ChiSquare_Independence : Test
    {
        public Test_ChiSquare_Independence(DataContainer data)
        {
            this.data = data;
            res = new List<String>();
        }

        public override string GetInfo()
        {
            String s = "Performs a Chi-square test to check if two datasets are independent.";
            return s;
        }

        public override void RunTest()
        {
            res.Add("Chi-square test for independence");

            //Error check
            if (data.GetNoSets() < 2)
            {
                res.Add("At least two datasets is required!");
                return;
            }

            for (int i1 = 0; i1 < data.GetNoSets(); i1++)
            {
                for (int i2 = 0; i2 < data.GetNoSets(); i2++)
                {
                    if (i1 != i2 && i1 < i2)
                    {
                        RunTest(i1, i2);
                    }
                }
            }
        }

        public void RunTest(int i1, int i2)
        {
            DataSet d1 = data.GetDataSet(i1);
            DataSet d2 = data.GetDataSet(i2);
            int n = Math.Min(d1.GetN(), d2.GetN());

            //Calculate row and column totals
            double[] rowTotals = new double[n];
            double[] colTotals = new double[2];
            double total = 0.0;
            for (int i = 0; i < n; i++)
            {
                rowTotals[i] = d1.GetValue(i) + d2.GetValue(i);
                colTotals[0] += d1.GetValue(i);
                colTotals[1] += d2.GetValue(i);
            }
            total = colTotals[0] + colTotals[1];
        
            //Create the chi-square table
            double chi2 = 0.0;
            double[,] tab = new double[n * 2, 7];
            for (int r = 0; r < n * 2; r += 2)
            {
                int row = r / 2;
                for (int c = 0; c < 2; c++)
                {
                    int col = 0;
                    DataSet d = d1;
                    if (c == 1) 
                    {
                        col = 1;
                        d = d2;
                    }
                
                    double O = d.GetValue(row);
                    double E = rowTotals[row] * colTotals[col] / total;

                    tab[r,0] = row+1;
                    tab[r,1] = col+1;
                    tab[r,2] = O;
                    tab[r,3] = E;
                    tab[r,4] = O-E;
                    tab[r,5] = Math.Pow(O-E, 2);
                    tab[r,6] = Math.Pow(O-E, 2) / E;
                
                    chi2 += tab[r,6];
                }           
            }
        
            //Get Critical Chi-square
            int DF = (2-1)*(n-1);
            ChiSquaredDistribution csd = new ChiSquaredDistribution(DF);
            double chi2c = csd.InverseRightProbability(alpha);

            //Calculate p
            double p = csd.RightProbability(chi2);

            //Results
            res.Add(";" + d1.GetName() + ";" + d2.GetName() + ";-");
            res.Add("N;" + d1.GetN() + ";" + d2.GetN() + ";-");
            res.Add("Mean;" + d1.GetMean().ToString("F2") + ";" + d2.GetMean().ToString("F2"));
            res.Add("StDev;" + d1.GetStDev().ToString("F2") + ";" + d2.GetStDev().ToString("F2"));
            res.Add("DoF;" + DF);
            res.Add("α;" + alpha + ";;-");
            res.Add("P-value;" + p.ToString("F3"));
            res.Add("Chi2-score;" + chi2.ToString("F2"));
            res.Add("Chi2-crit;" + chi2c.ToString("F2"));
            if (chi2 > chi2c)
            {
                res.Add("Result;Dependent (significance level " + p.ToString("F3") + ")");
            }
            else
            {
                res.Add("Result;Independent (significance level " + p.ToString("F3") + ")");
            }
            res.Add(";;;-");
        }
    }
}
